package mqueue

import (
	"encoding/json"
	"fmt"
	"github.com/streadway/amqp"
	"micro-bbs/datamodels"
	"micro-bbs/initialize"
	"micro-bbs/repositories"
	"micro-bbs/websocket"
	"time"
)

type RabbitInterfaceService interface {
	PushLoginLog(userInfo datamodels.BbsUser)         //推送登录日志
	PushUserPost(recordId int64)           			  //推送用户发帖确认
	PullLoginLog(number int)                          //消费登录日志
}

//初始化对象函数
func NewRabbitService() RabbitInterfaceService {
	return &rabbitService{
		userService:                  repositories.NewBbsUser(),
	}
}

type rabbitService struct {
	userService                  repositories.BbsUserInterface
}

//推送登录日志
func (this *rabbitService) PushLoginLog(userInfo datamodels.BbsUser) {
	//新建channel
	visitLogCh, err := initialize.MqClientUCenter.GetChannel()
	if err != nil {
		initialize.IrisLog.Errorf("[推送登录日志-创建channel失败]-[%s]", err.Error())
		return
	}
	defer visitLogCh.Close()

	//绑定队列
	q, queueErr := visitLogCh.QueueDeclare(
		initialize.Config.GetString("RabbitMQ.LoginLogQueue"), //name
		true,  //durable
		false, //delete when usused
		false, //exclusive
		false, //nowait
		nil,   //argments
	)
	if queueErr != nil {
		initialize.IrisLog.Errorf("[推送登录日志-创建queue失败]-[%s]", err.Error())
		return
	}

	//用户结构体
	type ExpInfo struct {
		FromUid       int64       `json:"fromUid"`       //发送用户id
		ToUid         int64       `json:"toUid"`         //接收用户id
		EventType     string      `json:"eventType"`     //事件类型
		HeadImg       string      `json:"head_img"`      //用户头像
		IsVip         int         `json:"is_vip"`        //是否VIP
		IsAdmin       int         `json:"is_admin"`      //是否管理员
		Date          string      `json:"date"`          //日期
		OtherInfo     interface{} `json:"otherInfo,omitempty"`
	}

	//封装body
	var exp ExpInfo
	exp.FromUid = userInfo.ID
	exp.ToUid = 0
	exp.EventType = "login_log_queue"
	exp.HeadImg = userInfo.HeadImg
	exp.IsVip = userInfo.IsVip
	exp.IsAdmin = userInfo.IsAdmin
	exp.Date = time.Unix(time.Now().Unix(), 0).Format("2006-01-02 15:04:05")
	//封装body

	jsonBytes, err := json.Marshal(exp)
	if err != nil {
		initialize.IrisLog.Errorf("[推送登录日志-json格式化失败]-[%s]", err.Error())
		return
	}

	//推送信息
	pushErr := visitLogCh.Publish(
		"",     // exchange
		q.Name, // routing key
		false,  // mandatory
		false,  // immediate
		amqp.Publishing{
			ContentType: "text/json",
			Body:        jsonBytes,
		})

	if pushErr != nil {
		initialize.IrisLog.Errorf("[推送登录日志-推送失败]-[%s]", err.Error())
		return
	}

	initialize.IrisLog.Infof("[推送登录日志-推送成功]-[%s]", string(jsonBytes))
}

//推送用户等级
func (this *rabbitService) PushUserPost(recordId int64) {
	//新建channel
	userPostCh, err := initialize.MqClientUCenter.GetChannel()
	if err != nil {
		initialize.IrisLog.Errorf("[推送确认帖子-创建channel失败]-[%s]", err.Error())
		return
	}
	defer userPostCh.Close()

	//绑定队列
	q, queueErr := userPostCh.QueueDeclare(
		initialize.Config.GetString("RabbitMQ.ConfirmPostQueue"), //name
		true,  //durable
		false, //delete when usused
		false, //exclusive
		false, //nowait
		nil,   //argments
	)
	if queueErr != nil {
		initialize.IrisLog.Errorf("[推送确认帖子-创建queue失败]-[%s]", err.Error())
		return
	}

	//通用消息结构体
	type MqInfo struct {
		RecordId       int64       `json:"record_id"`       //发帖成功记录id
	}

	//封装body
	var mqInfo MqInfo
	mqInfo.RecordId = recordId

	//封装body

	jsonBytes, err := json.Marshal(mqInfo)
	if err != nil {
		initialize.IrisLog.Errorf("[推送确认帖子-json格式化失败]-[%s]", err.Error())
		return
	}

	//推送信息
	pushErr := userPostCh.Publish(
		"",     // exchange
		q.Name, // routing key
		false,  // mandatory
		false,  // immediate
		amqp.Publishing{
			ContentType: "text/json",
			Body:        jsonBytes,
		})

	if pushErr != nil {
		initialize.IrisLog.Errorf("[推送确认帖子-推送失败]-[%s]", err.Error())
		return
	}

	initialize.IrisLog.Infof("[推送确认帖子-推送成功]-[%s]", string(jsonBytes))
}

//消费登录日志
func (this *rabbitService) PullLoginLog(number int) {
	//创建channel
	recordCh, err := initialize.MqClient.GetChannel()
	if err != nil {
		initialize.IrisLog.Infof("[消费登录日志MQ-创建channel失败]-[%s]", err.Error())
		return
	}
	defer recordCh.Close()

	//队列
	q, err := recordCh.QueueDeclare(
		initialize.Config.GetString("RabbitMQ.LoginLogQueue"), //name
		true,  //durable
		false, //delete when usused
		false, //exclusive
		false, //nowait
		nil,   //argments
	)
	if err != nil {
		initialize.IrisLog.Errorf("[消费登录日志MQ-创建queue失败]-[%s]", err.Error())
		return
	}

	//消费队列
	msgs, err := recordCh.Consume(
		q.Name, // queue
		"",     // consumer
		false,  // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)
	if err != nil {
		initialize.IrisLog.Errorf("[消费登录日志MQ-创建消费者失败]-[%s]", err.Error())
		return
	}

	forever := make(chan bool)
	go func() {
		for d := range msgs {
			time.Sleep(20 * time.Millisecond)
			//开始事务处理各种数据
			//绑定参数
			type bodyJson struct {
				FromUid       int64       `json:"fromUid"`       //发送用户id
				ToUid         int64       `json:"toUid"`         //接收用户id
				EventType     string      `json:"eventType"`     //事件类型
				HeadImg       string      `json:"head_img"`      //用户头像
				IsVip         int         `json:"is_vip"`        //是否VIP
				IsAdmin       int         `json:"is_admin"`      //是否管理员
				Date          string      `json:"date"`          //日期
				OtherInfo     interface{} `json:"otherInfo,omitempty"`
			}
			var info bodyJson

			if err := json.Unmarshal(d.Body, &info); err != nil {
				initialize.IrisLog.Errorf("[消费登录日志MQ-json数据失败]-[%s]", err.Error())
				continue
			}
			//推送数据到ws channel中
			fmt.Println("用户登录日志：",info)
			websocket.Ws.LoginLogMsg <- d.Body
			//如果Auto ack设为false。consumer在处理完消息后，调用msg.Ack(false)后消息才从queue中去除,如果是d.Ack(true)则自动清除。
			//即便当前消费者处理该消息发生意外，只要没有执行msg.Ack(false)那该消息就仍然在queue中，不会丢失。
			d.Ack(false)
		}
	}()
	initialize.IrisLog.Infof(" [消费登录日志MQ]-线程[%d]", number)
	<-forever
}